from PySide6.QtWidgets import (QTableWidget, QTableWidgetItem, QHeaderView, QWidget, 
                               QHBoxLayout, QPushButton, QAbstractItemView, QLabel, 
                               QSpinBox, QVBoxLayout)
from PySide6.QtGui import QIcon, QColor
from PySide6.QtCore import Qt, Signal
from common import config, exceptions

class CommonTableWidget(QWidget):
    # 定义信号
    pageChanged = Signal(int)  # 页码改变信号
    pageSizeChanged = Signal(int)  # 每页条数改变信号
    sortChanged = Signal(str)  # 排序信号, 排序字符串
    
    def __init__(self, parent=None, headers={}, pagination_position='bottom'):
        """
        headers: 键是列头, 值是配置, 可以设置text(文本), type(类型), width(宽度小数(百分比)), color(颜色), alignment(对齐方式)
        pagination_position: 分页控件位置, 可选值为'top','bottom', 'none', none代表不需要分页控件
        """
        super().__init__(parent)
        self.headers = headers
        self.setup_ui()
        
        # 分页相关属性
        self.current_page = 1
        self.page_size = config.DEFAULT_PAGE_SIZE
        self.total_pages = 1
        self.total_items = 0
        self.pagination_position = pagination_position  # 'top' 或 'bottom'
        self.sort_column = -1
        self.sort_order = Qt.AscendingOrder
        
        # 创建分页控件
        self.create_pagination_widget()
        
        # 设置布局
        self.setup_layout()
    
    def setup_ui(self):
        """设置表格UI"""
        # 创建表格
        self.table = QTableWidget()
        if self.headers:
            self.table.setColumnCount(len(self.headers.keys()))
            self.table.setHorizontalHeaderLabels(list(self.headers.keys()))

        # 设置行高
        self.table.verticalHeader().setDefaultSectionSize(50)
        # 设置列头高度
        self.table.horizontalHeader().setFixedHeight(40)
        # 隐藏垂直表头
        self.table.verticalHeader().setVisible(False)
        # 允许列头点击(排序)
        self.table.setSortingEnabled(False)
        self.table.horizontalHeader().setSectionsClickable(True)
        self.table.horizontalHeader().setSortIndicatorShown(True)
        self.table.horizontalHeader().sectionClicked.connect(self.on_sort_changed)
        
        # 设置列宽自适应
        self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch)
        # 行选择
        self.table.setSelectionBehavior(QTableWidget.SelectRows)
        # 交替行颜色
        self.table.setAlternatingRowColors(True)
        
        # 完全禁用编辑功能，包括双击编辑
        self.table.setEditTriggers(QAbstractItemView.NoEditTriggers)
        self._row_datas = {}
    
    def setup_layout(self):
        """设置整体布局"""
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # 根据位置添加控件
        if self.pagination_position == 'top':
            layout.addWidget(self.pagination_widget)
            layout.addWidget(self.table)
        elif self.pagination_position == 'bottom':
            layout.addWidget(self.table)
            layout.addWidget(self.pagination_widget)
        else:
            layout.addWidget(self.table)
        self.desc_label = QLabel()
        self.desc_label.setVisible(False)
        self.desc_label.setObjectName("descriptionLabel")
        self.desc_label.setWordWrap(True)  # 允许文字换行
        layout.addWidget(self.desc_label)
    
    def create_pagination_widget(self):
        """创建分页控件"""
        if self.pagination_position == 'none':
            return
        self.pagination_widget = QWidget()
        self.pagination_widget.setObjectName("paginationWidget")
        
        pagination_layout = QHBoxLayout(self.pagination_widget)
        pagination_layout.setContentsMargins(10, 8, 10, 8)
        pagination_layout.setSpacing(10)
        
        # 每页条数选择
        page_size_label = QLabel("每页条数:")
        page_size_label.setObjectName("paginationLabel")
        
        self.page_size_spin = QSpinBox()
        self.page_size_spin.setRange(config.MIN_PAGE_SIZE, config.MAX_PAGE_SIZE)
        self.page_size_spin.setValue(self.page_size)
        self.page_size_spin.setObjectName("pageSizeSpinBox")
        self.page_size_spin.valueChanged.connect(self.on_page_size_changed)
        
        # 页码信息
        self.page_info_label = QLabel()
        self.page_info_label.setObjectName("paginationLabel")
        
        # 上一页按钮
        self.prev_page_btn = QPushButton("上一页")
        self.prev_page_btn.setObjectName("prevPageButton")
        self.prev_page_btn.clicked.connect(self.prev_page)
        
        # 下一页按钮
        self.next_page_btn = QPushButton("下一页")
        self.next_page_btn.setObjectName("nextPageButton")
        self.next_page_btn.clicked.connect(self.next_page)
        
        # 添加到布局
        pagination_layout.addWidget(page_size_label)
        pagination_layout.addWidget(self.page_size_spin)
        pagination_layout.addStretch()
        pagination_layout.addWidget(self.page_info_label)
        pagination_layout.addWidget(self.prev_page_btn)
        pagination_layout.addWidget(self.next_page_btn)
        
        # 更新分页信息
        self.update_pagination_info()

    def adjust_column_widths(self):
        total_width = self.table.viewport().width()
        for i, header_value in enumerate(self.headers.values()):
            if "width" in header_value and 0 < float(header_value["width"]) < 1/2:
                self.table.setColumnWidth(i, int(header_value["width"] * total_width))
                self.table.horizontalHeader().setSectionResizeMode(i, QHeaderView.Fixed)

    def set_description(self, description):
        if description:
            self.desc_label.setText(description)
            self.desc_label.setVisible(True)
        else:
            self.desc_label.setText("")
            self.desc_label.setVisible(False)
        
    def update_pagination_info(self):
        """更新分页信息"""
        self.page_info_label.setText(f"第 {self.current_page}/{self.total_pages} 页，共 {self.total_items} 条")
        self.prev_page_btn.setEnabled(self.current_page > 1)
        self.next_page_btn.setEnabled(self.current_page < self.total_pages)
    
    def set_total_items(self, total):
        """设置总记录数"""
        self.total_items = total
        self.total_pages = (total + self.page_size - 1) // self.page_size
        if self.current_page > self.total_pages:
            self.current_page = max(1, self.total_pages)
        self.update_pagination_info()
    
    def prev_page(self):
        """上一页"""
        if self.current_page > 1:
            self.current_page -= 1
            self.update_pagination_info()
            self.pageChanged.emit(self.current_page)
    
    def next_page(self):
        """下一页"""
        if self.current_page < self.total_pages:
            self.current_page += 1
            self.update_pagination_info()
            self.pageChanged.emit(self.current_page)
    
    def on_page_size_changed(self, value):
        """每页条数改变"""
        self.page_size = value
        self.total_pages = (self.total_items + self.page_size - 1) // self.page_size
        if self.current_page > self.total_pages:
            self.current_page = max(1, self.total_pages)
        self.update_pagination_info()
        self.page_size_changed.emit(value)

    def on_sort_changed(self, column):
        """排序改变"""
        column_data = self.headers[self.table.horizontalHeaderItem(column).text()]
        if not column_data.get("sort", ""):
            self.table.horizontalHeader().setSortIndicator(-1, Qt.AscendingOrder)
            return
        if self.sort_column == column:
            if self.sort_order == Qt.AscendingOrder:
                self.sort_order = Qt.DescendingOrder
            elif self.sort_order == Qt.DescendingOrder:
                self.sort_order = None
                self.table.horizontalHeader().setSortIndicator(-1, Qt.AscendingOrder)
            else:
                self.sort_order = Qt.AscendingOrder
        else:
            self.sort_column = column
            self.sort_order = Qt.AscendingOrder
        self.sortChanged.emit(self.sort_string)

    @property
    def sort_string(self):
        """获取排序字符串"""
        if self.sort_order is None or self.sort_column == -1:
            return ""
        column_data = self.headers[self.table.horizontalHeaderItem(self.sort_column).text()]
        if not column_data.get("sort", ""):
            return ""
        if self.sort_order:
            return f"{'-' if self.sort_order == Qt.DescendingOrder else ''}{column_data['sort']}"
        else:
            return ""
    
    def get_page_info(self):
        """获取当前分页信息"""
        return {
            'current_page': self.current_page,
            'page_size': self.page_size,
            'total_pages': self.total_pages,
            'total_items': self.total_items
        }
    
    def add_action_buttons(self, row, buttons=[]):
        """添加操作按钮列"""
        if not buttons:
            return
        cell_widget = QWidget()
        layout = QHBoxLayout(cell_widget)
        layout.setContentsMargins(5, 2, 5, 2)
        layout.addStretch()
        for btn in buttons:
            if 'text' not in btn or 'callback' not in btn:
                continue
            qbtn = QPushButton(btn['text'])
            qbtn.setObjectName(btn.get('objectName', 'editButton'))
            qbtn.clicked.connect(lambda checked, callback=btn['callback']: callback(row))
            layout.addWidget(qbtn)
            layout.addStretch()
        #cell_widget.setStyleSheet("background: transparent;")
        self.table.setCellWidget(row, self.table.columnCount() - 1, cell_widget)

    def generate_table_item(self, col, data={}):
        "data原始值, 可以从中提取数据"
        if not isinstance(data, dict):
            item = QTableWidgetItem(str(data))
            item.setTextAlignment(Qt.AlignCenter)
            return item
        header_key = self.table.horizontalHeaderItem(col).text()
        #text
        text = self.headers[header_key].get("text", None)
        if text is None:
            return
        item_value = text(data)
        #type
        item_type = self.headers[header_key].get("type", "text")
        if item_type == "image": # 图片
            item = QTableWidgetItem()
            item.setIcon(QIcon(item_value))
        else:                                    # 文本   
            item = QTableWidgetItem(str(item_value))
        #alignment
        alignment = self.headers[header_key].get("alignment", Qt.AlignCenter)
        item.setTextAlignment(alignment)
        #width
        width = self.headers[header_key].get("width", "")
        if width:
            self.table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Fixed)
            self.table.setColumnWidth(col, width)
        #color
        color = self.headers[header_key].get("color", "")
        if color:
            if not isinstance(color, str):
                color = color(data)
            if isinstance(color, str):
                item.setForeground(QColor(color))
        return item
    
    def set_row_data(self, row, data):
        """设置行数据
        Args:
            row: 行号（整数）
            data: 数据（列表或字典）
        """
        if isinstance(data, dict):
            # 如果data是字典，根据列头获取对应的值
            for col in range(self.table.columnCount()):
                item = self.generate_table_item(col, data)
                if not item:
                    continue
                self.table.setItem(row, col, item)
        else:
            # 如果data是列表，使用原来的逻辑
            for col, value in enumerate(data):
                item = self.generate_table_item(col, value)
                if not item:
                    continue
                self.table.setItem(row, col, item)
        self._row_datas[row] = data
        self.adjust_column_widths()

    def get_row_data(self, row):
        if row < 0 or row > len(self._row_datas):
            return
        return self._row_datas.get(row, None)
    
    def update_row_data(self, row, row_data):
        if row < 0 or row > len(self._row_datas):
            return
        self._row_datas[row] = row_data

    def fresh_item(self, row, col):
        if row < 0 or row > len(self._row_datas):
            return
        item = self.generate_table_item(col, self._row_datas[row])
        self.table.setItem(row, col, item)
    
    # 重写QTableWidget的方法，使其代理到内部的table对象
    def setColumnCount(self, columns):
        self.table.setColumnCount(columns)
    
    def setRowCount(self, rows):
        self.table.setRowCount(rows)
    
    def setHorizontalHeaderLabels(self, labels):
        self.table.setHorizontalHeaderLabels(labels)
    
    def clear(self):
        self.table.clear()
        self._row_datas.clear()
    
    def rowCount(self):
        return self.table.rowCount()
    
    def columnCount(self):
        return self.table.columnCount()
    
    def item(self, row, column):
        return self.table.item(row, column)
    
    def setItem(self, row, column, item):
        self.table.setItem(row, column, item)
    
    def cellWidget(self, row, column):
        return self.table.cellWidget(row, column)
    
    def setCellWidget(self, row, column, widget):
        self.table.setCellWidget(row, column, widget)
    
    def horizontalHeader(self):
        return self.table.horizontalHeader()
    
    def verticalHeader(self):
        return self.table.verticalHeader()
    
    def selectedItems(self):
        return self.table.selectedItems()
    
    def selectedRanges(self):
        return self.table.selectedRanges()
    
    def setSelectionBehavior(self, behavior):
        self.table.setSelectionBehavior(behavior)
    
    def setSelectionMode(self, mode):
        self.table.setSelectionMode(mode)
    
    def setEditTriggers(self, triggers):
        self.table.setEditTriggers(triggers)

    def clearContents(self):
        self.table.clearContents()

    def setColumnHidden(self, col, bool):
        self.table.setColumnHidden(col, bool)

    def itemAt(self, pos):
        if not self.table.geometry().contains(pos):
            return None
        table_pos = self.table.viewport().mapFrom(self, pos)
        return self.table.itemAt(table_pos.x(), table_pos.y())

    def removeRow(self, row):
        self.table.removeRow(row)
        self._row_datas.pop(row)

    def showEvent(self, event):
        super().showEvent(event)
        self.adjust_column_widths()

    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.adjust_column_widths()
